const {ccclass, property} = cc._decorator;

import DebugHelper from "./DebugHelper"
import BubbleUtil from "./BubbleUtil"
import AppConfig from "../AppConfig"
import App from "../App"

import {Bubble} from "../../prefabs"

@ccclass
export default class Game extends cc.Component {
    @property(cc.Prefab)
    bubblePrefab: cc.Prefab = null;

    config:AppConfig = null;

    loadResourceFinished: boolean = false;
    _bubbleMap:number[][] = [];
    _designResolution:cc.Vec2 = cc.v2(0,0);
    _offsetX = -360;
    _offsetY = 0;


    _g: cc.Graphics = null;
    _isPress: boolean = false;
    _touchPoint: cc.Vec2 = cc.Vec2.ZERO;
    normalizeVec: cc.Vec2 = cc.Vec2.ZERO;
    bubbleMap: cc.Node[][] = [];
    pathBubbles:cc.Node[] = [];
    pathAdjustBubbles:cc.Node[] = [];
    path:cc.Vec2[] = [];


    currBubble:cc.Node = null;
    adjustBubble:cc.Node = null;
    readInitPos:cc.Vec2 = cc.v2(0, -288);
        // readInitPos:cc.Vec2 = cc.v2(0, 0);

    touchMoveEventInterval:number = 0.03; // 1 / 30. 设置交互30fps
    touchMoveEventElapse:number = 0;

    cancelFire:boolean = false;

    // 逻辑帧属性
    frameRate:number = 30;          // 帧率
    frameTime:number = 0.0333; // 一帧耗时
    frameIndex:number = 0;       // 记录当前帧
    frameTimeElapse:number = 0; // 记录当前帧已消耗的时间
    
    realFrameRate:number = 0;   // 实际帧率
    tickFrameIndex:number = 0;  // 记录1s内实际进行的帧数
    timeCost:number = 0;       // 同来累计时间，每>=1时就重新计数，用来计算realFrameRate

    // 根据map创建对应的bubble node
    loadBubbleMap() {
        for(let i = 0; i < this._bubbleMap.length; ++i)
        {
            let rowVec = this._bubbleMap[i];
            let bubbleVec = [];
            for(let j = 0; j < rowVec.length; ++j)
            {
                var newBubble = cc.instantiate(this.bubblePrefab);
                newBubble.setPosition(BubbleUtil.getPosByRowAndCol(i,j, this._bubbleMap.length));
                let bubble = newBubble.getComponent("Bubble");
                bubble.type = rowVec[j];
                bubble.row = i;
                bubble.col = j;
                newBubble.parent = this.node;
                bubbleVec.push(newBubble);
            }
            this.bubbleMap.push(bubbleVec);
        }

        // this.UpdateBubbleMap();
    }

    // 如果bubble map消除了n行，需要移动bubble
    UpdateBubbleMap() {
        for(let i = 0; i < this.bubbleMap.length; ++i)
        {
            let rowVec = this.bubbleMap[i];
            for(let j = 0; j < rowVec.length; ++j)
            {
                let bubble = rowVec[j];
                if(bubble != null)
                {
                    let newPos = BubbleUtil.getPosByRowAndCol(i,j, this.bubbleMap.length);
                    let oldPos = bubble.getPosition();
                    newPos.x = oldPos.x;
                    cc.tween(bubble)
                    .to(1, {position: cc.v3(newPos.x, newPos.y, 0)})
                    .call(()=>{
                        // cc.log("Game|UpdateBubbleMap|" + newPos.toString());
                        bubble.setPosition(newPos);
                    }).start();
                }
            }
        }
    }

    loadReadBubble()
    {
        var newBubble = cc.instantiate(this.bubblePrefab);
        var pos = cc.v2(24,-330);
        newBubble.setPosition(pos);
        newBubble.getComponent("Bubble").type = 0;
        newBubble.parent = this.node;
    }


    onTouchStart(event:cc.Event.EventTouch)
    {
        if(this.currBubble == null)
        {
            this._isPress = true;
            this._touchPoint.x = event.getLocationX();
            this._touchPoint.y = event.getLocationY();
            BubbleUtil.touchPointTransform(this._touchPoint);
            // 归一化，获取方向单位向量
            this.normalize();
            if(this.normalizeVec.y <= 0)
            {
                return;
            }
            cc.log("Game|onTouchStart|" + this.normalizeVec.toString())
            if(BubbleUtil.judgeCancelFire(this.normalizeVec))
            {
                this.cancel();
            }
            else
            {
                this.drawAimLine(this._touchPoint);
            }
        }
    }

    onTouchEnd(event:cc.Event.EventTouch)
    {
        if(this.currBubble == null)
        {
            this._isPress = false;
            this.clearAimLine();
            
            if(this.normalizeVec.y <= 0)
            {
                return;
            }

            if(!this.cancelFire)
            {
                cc.log("Game|onTouchEnd|" + this.normalizeVec.toString())
                this.fire();
            }
            else
            {
                // 重置变量
                this.cancelFire = false;
            }
        }
    }

    onTouchMove(event:cc.Event.EventTouch)
    {
        if(this.currBubble == null)
        {
            cc.log("onTouchMove|" + this.touchMoveEventElapse);
            if(this._isPress && this.touchMoveEventElapse >= this.touchMoveEventInterval)
            {
                cc.log("OnMouseMove");
                this.touchMoveEventElapse = 0;
                this._touchPoint.x = event.getLocationX();
                this._touchPoint.y = event.getLocationY();
                BubbleUtil.touchPointTransform(this._touchPoint);
                // 归一化，获取方向单位向量
                this.normalize();
                if(this.normalizeVec.y <= 0)
                {
                    return;
                }

                if(BubbleUtil.judgeCancelFire(this.normalizeVec))
                {
                    this.cancel();
                }
                else
                {
                    this.drawAimLine(this._touchPoint);
                }
            }
        }
    }

    drawAimLine(pos:cc.Vec2)
    {
        this.clearAimLine();
        this.findPath();
        this._g.moveTo(this.path[0].x, this.path[0].y);
        for(let i = 1; i < this.path.length; ++i)
        {
            this._g.lineTo(this.path[i].x, this.path[i].y);
        }
        this._g.stroke();
    }

    clearAimLine()
    {
        this.clearPath();
        if(this.adjustBubble != null)
        {
            this.adjustBubble.destroy();
            this.adjustBubble = null;
        }
    }

    normalize()
    {
        let len = Math.sqrt((this._touchPoint.x - this.readInitPos.x) * (this._touchPoint.x - this.readInitPos.x)
            + (this._touchPoint.y - this.readInitPos.y) * (this._touchPoint.y - this.readInitPos.y));
        this.normalizeVec.x = (this._touchPoint.x - this.readInitPos.x) / len;
        this.normalizeVec.y = (this._touchPoint.y - this.readInitPos.y) / len;
    }

    clearPath()
    {
        this._g.clear();

        this.pathBubbles.forEach(node => {
            node.parent = null;
            node.destroy();
        });
        this.pathBubbles = [];

        this.pathAdjustBubbles.forEach(node => {
            node.parent = null;
            node.destroy();
        });
        this.pathAdjustBubbles = [];
    }

    findPath()
    {
        let tmpNormalizeVec = cc.v2(this.normalizeVec);
        let currPos = cc.v2(this.readInitPos);
        this.path = [];
        this.path.push(cc.v2(currPos));
        let stepLen = 65.4 * 0.5;
        let leftBorderline = -360 + 32.7;
        let rightBorderline = 360 - 32.7;
        for(let i = 0; i < 50; ++i)
        {
            let nowX = 0;
            let nowY = 0;
            let deltaX = stepLen * tmpNormalizeVec.x;
            let deltaY = stepLen * tmpNormalizeVec.y;
            if(deltaX + currPos.x >= rightBorderline)
            {
                nowX = rightBorderline;
                nowY = (rightBorderline - currPos.x) / tmpNormalizeVec.x * tmpNormalizeVec.y + currPos.y;
            }
            else if(deltaX + currPos.x <= leftBorderline)
            {
                nowX = leftBorderline;
                nowY = Math.abs((leftBorderline - currPos.x) / tmpNormalizeVec.x) * tmpNormalizeVec.y + currPos.y;
            }
            else
            {
                nowX = deltaX + currPos.x;
                nowY = deltaY + currPos.y;
            }

            if(this.config.showFindPathPoint)
            {
                this._g.fillColor = cc.Color.BLUE;
                this._g.circle(nowX, nowY, 10);
                this._g.fill();
            }

            if(this.config.showFindPathBubble)
            {
                let node = cc.instantiate(this.bubblePrefab);
                node.getComponent("Bubble").type = 2;
                node.setPosition(cc.v2(nowX, nowY));
                node.parent = this.node;
                node.opacity = 100;
                node.color = cc.Color.BLUE;
                this.pathBubbles.push(node);
            }


            currPos.x = nowX;
            currPos.y = nowY;

            let rowAndCol = BubbleUtil.getRowAndColByPos(nowX, nowY, this.bubbleMap.length);
            
            cc.log("findPath| ----1----- " + i + " + realPos= " + currPos.toString() + "rowAndCol=" + rowAndCol.toString());

            if(this.config.showAdjustPathBubble)
            {
                let node = cc.instantiate(this.bubblePrefab);
                node.getComponent("Bubble").type = 2;
                node.getComponent("Bubble").index = i;
                node.setPosition(BubbleUtil.getPosByRowAndCol(rowAndCol.x, rowAndCol.y, this.bubbleMap.length));
                node.parent = this.node;
                node.opacity = 100;
                this.pathAdjustBubbles.push(node);
            }


            if(BubbleUtil.checkPointValid(nowX, nowY, rowAndCol.x, rowAndCol.y, this.bubbleMap.length))
            {
                cc.log("findPath|---------2------ checkPointValid True|i = " + i + "rowAndCol=" + rowAndCol.toString());

                let result = BubbleUtil.isCollision(this.bubbleMap, rowAndCol.x, rowAndCol.y, currPos);
                if(result)
                {
                    cc.log("findPath|collision, rowAndCol=" + rowAndCol.toString());
                    this.adjustBubble = cc.instantiate(this.bubblePrefab);
                    this.adjustBubble.getComponent("Bubble").type = 1;
                    this.adjustBubble.parent = this.node;
                    // this.adjustBubble.opacity = 100;
                    this.adjustBubble.setPosition(BubbleUtil.getPosByRowAndCol(rowAndCol.x, rowAndCol.y, this.bubbleMap.length));
                    break;
                }
            }

            if(currPos.x + 32.7 >= 360)
            {
                this.path.push(cc.v2(currPos));
                tmpNormalizeVec.x *= -1;
            }
            if(currPos.x - 32.7 <= -360)
            {
                tmpNormalizeVec.x *= -1;
                this.path.push(cc.v2(currPos));
            }
        }
        this.path.push(cc.v2(currPos));
        cc.log("findPath|path node size " + this.path.length);
    }
    // 发射
    fire()
    {
        cc.log("Game|fire");
        if(this.currBubble == null)
        {
            cc.log("Game|fire| fire new bubble");
            this.currBubble = cc.instantiate(this.bubblePrefab);
            this.currBubble.parent = this.node;
            this.currBubble.setPosition(this.readInitPos);
        }
        else
        {

            cc.log("Game|fire| has currBubble");
        }
    }

    // 取消发射
    cancel()
    {
        this.cancelFire = true;
        this.clearAimLine();
    }

    // LIFE-CYCLE CALLBACKS:

    onLoad () {
        cc.log("Game|onLoad");
        this.config = App.instance.appConfig;
        
        this._g = this.node.getComponent(cc.Graphics);
        cc.log(this._g instanceof cc.Graphics);

        let debugHelper:DebugHelper = this.node.getComponent(DebugHelper);

        // this.node.on('mousedown', this.OnMouseDown, this);
        // this.node.on('mouseup', debugHelper.OnTouchEnd, debugHelper);
        // this.node.on('mousemove', this.OnMouseMove, this);

        this.node.on('touchstart', this.onTouchStart, this);
        this.node.on('touchmove', this.onTouchMove, this);
        this.node.on('touchend', this.onTouchEnd, this);
    }

    start () {
        // while(!this.loadResourceFinished)
        // {
            
        // }
        cc.log("Game|start");
        this._g.moveTo(this.readInitPos.x, this.readInitPos.y);
        this._g.lineTo(0, 200);
        this._g.stroke();

        this._bubbleMap = [
            [0,0,0,0,0,0,0,0,0,0,],
            [0,0,0,0,0,0,0,0,2,0],
            [0,0,0,1,0,0,0,0,2,0,0],
            [0,0,0,0,1,0,0,0,2,0],
            [0,0,0,0,1,0,0,0,2,0],
            [0,0,0,0,0,0,0,0,0,0],
            [0,0,0,0,1,0,0,0,2,0],
            // [0,0,0,0,1,0,0,0,2,0],
            // [0,0,0,0,1,0,0,0,2,0],
            // [0,0,0,0,1,0,0,0,2,0],
            // [0,0,0,0,1,0,0,0,2,0],
            // [0,0,0,0,1,0,0,0,2,0],
            // [0,0,0,0,1,0,0,0,2,0],
            // [0,0,0,0,1,0,0,0,2,0],
            // [0,0,0,0,1,0,0,0,2,0],
            // [0,0,0,0,1,0,0,0,2,0],
            // [0,0,0,0,1,0,0,0,2,0],
            // [0,0,0,0,1,0,0,0,2,0],
            // [0,0,0,0,1,0,0,0,2,0],
            // [0,0,0,0,1,0,0,0,2,0],
            // [0,0,0,0,1,0,0,0,2,0],
            // [0,0,0,0,1,0,0,0,2,0],
            // [0,0,0,0,1,0,0,0,2,0,1],
        ];

        this.loadBubbleMap();
        // this.loadReadBubble();
    }

    // 每logic frame的处理方法
    logicUpdate()
    {
        let stepLen = 65.4;

        if(this.currBubble != null)
        {
            let oldPos = this.currBubble.getPosition();
            if(oldPos.y > 640)
            {
                this.currBubble.parent = null;
                this.currBubble.destroy();
                this.currBubble = null;
                return;
            }
            let x = oldPos.x + stepLen * this.normalizeVec.x;
            let y = oldPos.y + stepLen * this.normalizeVec.y;

            if(x + 32.7 >= 360)
            {
                this.normalizeVec.x *= -1;
            }

            if(x - 32.7 <= -360)
            {
                this.normalizeVec.x *= -1;
            }

            this.currBubble.setPosition(x, y);
        }
    }

    update (dt) {
        this.touchMoveEventElapse += dt;
        this.frameTimeElapse += dt;
        this.timeCost += dt;

        if(this.frameTimeElapse >= this.frameTime)
        {
            // 由于渲染的阻塞，可能造成逻辑帧达不到预期值,需要计算出真实的逻辑帧数量，进行补偿
            let frameNum = Math.floor(this.frameTimeElapse / this.frameTime);
            this.frameTimeElapse -= (this.frameTime * frameNum);

            this.frameIndex += frameNum;
            this.tickFrameIndex += frameNum;

            for(let i = 0; i < frameNum; ++i)
            {
                this.logicUpdate();
            }
        }

        if(this.timeCost >= 1)
        {
            this.realFrameRate = this.tickFrameIndex;
            this.tickFrameIndex = 0;
            this.timeCost -= 1;
            cc.warn("Game|update|realFrameRate=" + this.realFrameRate);
        }
    }
}
